# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##--------------------------------------------------------------------------##
__docformat__ = "restructuredtext en"

from .. import pilelib as stack
from ..utillib.misc import kwdefault
from ..packlib import info as cs
from .. import comparecards as cmp_cards
from .. import helpstrings as hs


class Rank_Foundation(stack.AbstractFoundation):
    """
    Pile support finishing cards from other pile groups and builds down in
    rank order by same suit with trash cards able to swap. This pile is a
    foundation pile found in Hanafuda (Flower) style games.

    :CVariables:
      _BOTTOM_IMAGE_ :  str
        use a suit bottom image for stack.
    """

    def __init__(self, x, y, game, suit, strict=True, **cap):
        """
        __init__(x, y, game, suit[, strict=True, offset=(0, 0),
          base_rank=FOURTH, dir=-1]) -> None

        :Parameters:
          x : int
            left x-coordinate.
          y : int
            top y-coordinate.
          game : Game
            current Game.
          suit : int
            pile's suit and base_suit capability

        :Keywords:
          strict : bool
            All suits or just Willow suit swap trash cards.
          offset : tuple
            offset from left and offset from top

        :seealso:
          Module pysollib.stackcaps with details of *capability* keywords.
        """
        kwdefault(cap, dir=-1, suit=suit, base_rank=cs.FOURTH)
        super(Rank_Foundation, self).__init__(x, y, game, **cap)
        self._strict = strict

    def _sequence(self, cards):
        """
        _sequence(cards) -> bool

        Cards are isFlowerSequence according _strictness and *capability*.

        :Parameters:
          cards : tuple
            cards from sending pile

        :returns: accept card sequence?
        """
        return cmp_cards.isFlowerSequence(cards, strict=self._strict,
                                          **self.cap)

    @property
    def _helpString(self):
        """
        _helpString -> str

        :returns: helpful string about pile for its canvas label.
        """
        build = hs.BUILD_SS_DICT.get(hs.dir_(self.cap['dir']), '')
        swaps = hs.SWAPS_DICT.get(int(self._strict), '')
        return "{0} {1}".format(build, swaps).strip()


class Suit_Foundation(stack.AbstractFoundation):
    """
    Pile support finishing cards from other pile groups and builds up in suit
    order by same rank. This pile is a foundation pile found in Hanafuda
    (Flower) style games.

    :CVariables:
      _BOTTOM_IMAGE_: str
        use a rank bottom image for stack.
    """
    _BOTTOM_IMAGE_ = 'rank'

    def __init__(self, x, y, game, rank, **cap):
        """
        __init__(x, y, game, rank[, strict=True, offset=(0, 0),
          max_cards=SUITS, rank=rank base_rank=rank, suit=ANY,
          base_suit=PINE}]) -> None

        :Parameters:
          x : int
            left x-coordinate.
          y : int
            top y-coordinate.
          game : Game
            current Game.
          suit : int
            pile's suit and base_suit capability

        :Keywords:
          strict : bool
            All suits or just Willow suit swap trash cards.
          offset : tuple
            offset from left and offset from top

        :seealso:
          Module pysollib.stackcaps with details of *capability* keywords.
        """
        suits = len(game['suits'])
        kwdefault(cap, max_cards=suits, rank=rank, base_rank=rank,
                  base_suit=cs.PINE, suit=cs.ANY)
        super(Suit_Foundation, self).__init__(x, y, game, **cap)

    def _sequence(self, cards):
        """
        _sequence(cards) -> bool

        Cards are isRankSuitSequence according _strictness and *capability*.

        :Parameters:
          cards : tuple
            cards from sending pile

        :returns: accept card sequence?
        """
        return cmp_cards.isRankSuitSequence(cards, **self.cap)

    @property
    def _helpString(self):
        """
        _helpString -> str

        :returns: helpful string about pile for its canvas label.
        """
        return hs.BUILD_SUIT_DICT.get(hs.dir_(self.cap['dir']), '')


class Pagoda_Foundation(stack.SS_Foundation):

    def _sequence(self, cards):
        """
        _sequence(cards) -> bool

        Cards are isFlowerSequence according _strictness and *capability*. In
        addition cards build in dir then match then reverse dir.

        :Parameters:
          cards : tuple
            cards from sending pile

        :returns: accept card sequence?
        """
        cap_dir = self.cap['dir']
        if len(self.cards) > 4:
            self.cap['dir'] *= -1
        elif len(self.cards) == 4:
            self.cap['dir'] = 0
        r = super(Pagoda_Foundation, self)._sequence(cards)
        self.cap['dir'] = cap_dir
        return r


class MatsuKiri_Foundation(Rank_Foundation):

    def __init__(self, x, y, game, rank, strict=True, **cap):
        """
        __init__(x, y, game, rank[, strict=True, offset=(0, 0),
          max_cards=SUITS, rank=rank base_rank=rank, suit=ANY,
          base_suit=PINE}]) -> None

        :Parameters:
          x : int
            left x-coordinate.
          y : int
            top y-coordinate.
          game : Game
            current Game.
          suit : int
            pile's suit and base_suit capability

        :Keywords:
          strict : bool
            All suits or just Willow suit swap trash cards.
          offset : tuple
            offset from left and offset from top

        :seealso:
          Module pysollib.stackcaps with details of *capability* keywords.
        """
        ncards = len(game['ncards'])
        kwdefault(cap, suit=cs.ANY, max_move=0, max_cards=ncards,
                         max_accept=4, min_accept=4, base_suit=cs.PINE, dir=1)
        super(MatsuKiri_Foundation, self).__init__(x, y, game, strict=strict,
                                                   **cap)

    def _sequence(self, cards):
        """
        _sequence(cards) -> bool

        Cards are isFlowerSequence according _strictness and *capability*. In
        addition cards build in dir then match then reverse dir.

        :Parameters:
          cards : tuple
            cards from sending pile

        :returns: accept card sequence?
        """
        if not super(MatsuKiri_Foundation, self)._sequence(cards[1:]):
            return False
        return not self.cards or cmp_cards.isSuitSequence(cards[:2], dir=1)


class VarySuit_Foundation(Suit_Foundation):
    """
    Build up in suit by same rank. Play top except base.

    :CVariables:
      _BOTTOM_IMAGE_: str
        use a rank bottom image for stack.
    """
    _BOTTOM_IMAGE_ = 'rank'

    def __init__(self, x, y, game, rank, **cap):
        """
        __init__(x, y, game, rank[, strict=True, offset=(0, 0),
          mod=12, base_suit=cs.ANY, min_accept=1}]) -> None

        :Parameters:
          x : int
            left x-coordinate.
          y : int
            top y-coordinate.
          game : Game
            current Game.
          suit : int
            pile's suit and base_suit capability

        :Keywords:
          strict : bool
            All suits or just Willow suit swap trash cards.
          offset : tuple
            offset from left and offset from top

        :seealso:
          Module pysollib.stackcaps with details of *capability* keywords.
        """
        kwdefault(cap, mod=12, base_suit=cs.ANY, min_accept=1)
        super(VarySuit_Foundation, self).__init__(x, y, game, rank,
                                                         **cap)

    def cardsBuild(self, from_stack, cards):
        """
        cardsBuild(from_stack, cards) -> bool

        Sets a base_rank for pile group when ANY, then checks
        parent.cardsBuild().

        :Paramaters:
          from_stack : pysollib.stack.Stack
            sending pile
          cards : tuple
            cards from sending pile

        :returns: pile accepts ``cards``?
        """
        if self.cap['base_suit'] == cs.ANY:
            self.game._save_stack_caps(self.game.s['foundations'],
                                       base_suit=cards[0]['rank'])
        return super(VarySuit_Foundation, self).cardsBuild(from_stack,
                                                                 cards)


class BraidSuit_Foundation(Suit_Foundation):
    """
    Build in suit by same rank. Play none. 2nd card sets suit direction.

    :CVariables:
      _BOTTOM_IMAGE_: str
        use a rank bottom image for stack.
    """

    def __init__(self, x, y, game, suit, **kw):
        """
        __init__(x, y, game, rank[, offset=(0, 0),
          mod=12, base_suit=cs.ANY, min_accept=1}]) -> None

        :Parameters:
          x : int
            left x-coordinate.
          y : int
            top y-coordinate.
          game : Game
            current Game.
          suit : int
            pile's suit and base_suit capability

        :Keywords:
          offset : tuple
            offset from left and offset from top

        :seealso:
          Module pysollib.stackcaps with details of *capability* keywords.
        """
        kwdefault(kw, dir=0, max_move=0)
        super(BraidSuit_Foundation, self).__init__(x, y, game, suit, **kw)

    def cardsBuild(self, from_stack, cards):
        """
        cardsBuild(from_stack, cards) -> bool

        Check parent.cardsBuild() and cards isSequence() with top card
        acccording to *capabilities*. Set cap['dir'] for all piles when pile has
        cards and cap['dir'] not set

        :Paramaters:
          from_stack : pysollib.stack.Stack
            sending pile
          cards : tuple
            cards from sending pile

        :returns: pile accepts ``cards``?
        """
        if self.cap['dir'] == 0 and self.cards:
            self.game._save_stack_caps(self.game.s['foundations'],
                          dir=cmp_cards.getDirection(self.cards[-1:] + cards,
                                                     attr='suit'))
        return super(BraidSuit_Foundation, self).cardsBuild(from_stack, cards)


class Rank_RowStack(stack.SequenceRowStack):
    """
    Pile supports playing and building sequences. The playing piles build up
    in rank order alone allowing Third and Fourth rank tash cards to swap.

    :CVariables:
      _BOTTOM_IMAGE_: str
        use a blank bottom image for stack.
    """

    def __init__(self, x, y, game, strict=True, **cap):
        """
        __init__(x, y, game[, strict=True, offset=(0, YOFFSET), dir=1]) ->
          None

        :Parameters:
          x : int
            left x-coordinate.
          y : int
            top y-coordinate.
          game : Game
            current Game.

        :Keywords:
          strict : bool
            All suits or just Willow suit swap trash cards.
          offset : tuple
            offset from left and offset from top

        seealso::
          Module pysollib.stackcaps with details of *capability* keywords.
        """
        cap.setdefault('dir', 1)
        super(Rank_RowStack, self).__init__(x, y, game, **cap)
        self.strict = strict

    def _sequence(self, cards):
        """
        _sequence(cards) -> bool

        :Parameters:
          cards : tuple
            cards from sending pile

        :returns: always True.
        """
        return True

    def _build_sequence(self, cards):
        """
        _build_sequence(cards) -> bool

        Cards are isRankSuitSequence according _strictness and *capability*.

        :Parameters:
          cards : tuple
            cards from sending pile

        :returns: right sequence?
        """
        return cmp_cards.isFlowerSequence(cards, strict=self.strict,
                                          **self.cap)

    @property
    def _helpString(self):
        """
        _helpString -> str

        :returns: helpful string about pile for its canvas label.
        """
        build = hs.BUILD_RK_DICT.get(hs.dir_(self.cap['dir']), '')
        swaps = hs.SWAPS_DICT.get(int(self._strictness), '')
        return "{0} {1}".format(build, swaps).strip()


class RankSS_RowStack(Rank_RowStack):
    """
    Pile supports playing and building sequences. The playing piles build up
    in rank order by sames suit allowing Third and Fourth rank tash cards to
    swap.

    :CVariables:
      _BOTTOM_IMAGE_: str
        use a blank bottom image for stack.
    """

    def _build_sequence(self, cards):
        """
        _build_sequence(cards) -> bool

        Cards are isRankSuitSequence according _strictness and *capability*.

        :Parameters:
          cards : tuple
            cards from sending pile

        :returns: right sequence?
        """
        return (cmp_cards.isSameSuit(cards) and
                super(RankSS_RowStack, self)._build_sequence(cards))

    @property
    def _helpString(self):
        """
        _helpString -> str

        :returns: helpful string about pile for its canvas label.
        """
        build = hs.BUILD_SS_DICT.get(hs.dir_(self.cap['dir']), '')
        swaps = hs.SWAPS_DICT.get(int(self._strictness), '')
        return "{0} {1}".format(build, swaps).strip()


class Suit_RowStack(stack.SequenceRowStack):
    """
    Pile supports playing and building sequences. The playing piles build down
    in suit order by same rank.

    :CVariables:
      _BOTTOM_IMAGE_ : str
        use a blank bottom image for stack.
    """

    def _sequence(self, cards):
        """
        _sequence(cards) -> bool

        :Parameters:
          cards : tuple
            cards from sending pile

        :returns: always True.
        """
        return True

    def _build_sequence(self, cards):
        """
        _build_sequence(cardsle) -> bool

        Cards are isRankSuitSequence according *capability*.

        :Parameters:
          cards : tuple
            cards from sending pile

        :returns: right sequence?
        """
        return cmp_cards.isRankSuitSequence(cards, **self.cap)

    @property
    def _helpString(self):
        """
        _helpString -> str

        :returns: helpful string about pile for its canvas label.
        """
        return hs.BUILD_SUIT_DICT.get(hs.dir_(self.cap['dir']), '')


class GW_RankSS_RowStack(RankSS_RowStack):
    """
    Pile supports playing and building sequences. The playing piles build down
    in rank order by same suit with Gaji wild.

    :CVariables:
      _BOTTOM_IMAGE_ : str
        use a blank bottom image for stack.

    :note: was Gaji_RowStack
    """

    def _build_sequence(self, cards):
        """
        _build_sequence(cards) -> bool

        Cards are isRankSuitSequence according _strictness and *capability*.

        :Parameters:
          cards : tuple
            cards from sending pile

        :returns: right sequence?
        """
        if any(cmp_cards.isGaji(card) for card in cards[:2]):
            return True
        return super(GW_RankSS_RowStack, self)._build_sequence(cards)


class DropRankSS_RowStack(RankSS_RowStack):
    """
    Pile supports playing and building sequences. The playing piles build down
    in rank order by same suit with full seq drop on `s.foundations`.

    :CVariables:
      _BOTTOM_IMAGE_ : str
        use a blank bottom image for stack.

    :note: was MatsuKiri_RowStack
    """

    def cardsDrop(self, stacks):
        """
        _cardsDrop(stacks) -> tuple

        Get foundation pile that 4 cards in `_build_sequence` can drop on.

        :Parameters:
          stacks : tuple
            cards that may recieve cards

        :returns: tuple of pile and 4 or None and 0
        """
        pile = self.SEQUENCE
        f = self.game.s['foundations'][0]
        suit = cs.PINE if not f.cards else f.TOPCARD['suit'] + 1
        if (pile and len(pile) > 3 and self._build_sequence(pile[-4:]) and
            cmp_cards.isSameSuit(pile[-4:], suit=suit)):
            return (f, 4,)
        return (None, 0,)


class GreatWall_RowStack(Rank_RowStack):
    """
    Pile supports playing and building sequences. The playing piles build down
    in rank order or suit order.

    :CVariables:
      _BOTTOM_IMAGE_ : str
        use a blank bottom image for stack.

    :note: was MatsuKiri_RowStack
    """

    def _build_sequence(self, cards):
        """
        _build_sequence(cards) -> bool

        Cards are isRankSuitSequence or isFlowerSequence according _strictness
        and *capability*.

        :Parameters:
          cards : tuple
            cards from sending pile

        :returns: right sequence?
        """
        if cmp_cards.isSameRank(cards):
            return cmp_cards.isRankSuitSequence(cards, dir=1, mod=12)
        return super(GreatWall_RowStack, self)._sequence(cards)


class JapaneseGarden_RowStack(stack.NotFromRowStackBuildMethod, Rank_RowStack):
    """
    Pile supports playing and building sequences. The playing piles build down
    in rank order but not on another `s.rows`.

    :CVariables:
      _BOTTOM_IMAGE_ : str
        use a blank bottom image for stack.

    :note: was MatsuKiri_RowStack
    """
    pass